﻿using System;
using System.Windows;
using System.Windows.Input;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Collections.Generic;
using System.Drawing;
using System.Collections;
using PSE.Framework.UI.Resources;
using System.Windows.Controls;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
    public class SinacorReportWindow : SinacorWindow
    {
        #region Fields

        private ReportDocument _reportDocument = null;
        private CrystalReportViewer _crViewer = null;

        private List<SinacorReportDataObjects> _dataObjects;
        private List<SinacorReportFormatObjects> _formatObjects;
        private List<SinacorReportParameterValue> _parametersValues;
        private List<SinacorReportDataSource> _sinacorReportDataSource;

        private String _reportName;
        private Report.Settings _style = null;
        private Boolean _columnMappedChecked;
        private String _reportTitleResourceKey;

        #endregion

        #region Constructor

        /// <summary>
        /// Não permitir a utilização do contrustor padrão
        /// </summary>
        private SinacorReportWindow()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reportName"></param>
        /// <param name="reportTitleResourceKey"></param>
        public SinacorReportWindow(String reportName, string reportTitleResourceKey)
        {

            this.SetResourceReference(StyleProperty, "ControlReportWindow");

            if (string.IsNullOrEmpty(this._reportTitleResourceKey))
            {
                //como um título não foi informado, assumir um título padrão
                this._reportTitleResourceKey = reportTitleResourceKey;
            }

            //atribuir um title a janela
            this.SetResourceReference(Window.TitleProperty, this._reportTitleResourceKey);

            this.WindowStartupLocation = WindowStartupLocation.CenterScreen;

            this.CommandBindings.Add(new CommandBinding(SinacorWindowCommands.Close, btnClose_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.Export, btnExport_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.Print, btnPrint_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.GroupTree, btnGroupTree_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.First, btnFirst_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.Previous, btnPrevious_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.Next, btnNext_Click));
            this.CommandBindings.Add(new CommandBinding(SinacorReportCommands.Last, btnLast_Click));

            this._reportDocument = new ReportDocument();
            this._reportName = reportName;

            this._style = Report.Settings.Default;

            this.Initialized += new EventHandler(SinacorReportParameterWindow_Initialized);
        }

        void SinacorReportParameterWindow_Initialized(object sender, EventArgs e)
        {
            SinacorWindow ownerWindow = this.Owner as SinacorWindow;
            if (ownerWindow == null)
                throw new Exception("The Owner of the Window must be informed.");

            this.ModuleId = ownerWindow.ModuleId;
            this.ModulePlus = ownerWindow.ModulePlus;
            this.SetMenuHeader(ownerWindow.MenuHeader, this._reportTitleResourceKey);
        }

        /// <summary>
        /// Criar uma nova SinacorReportWindow
        /// </summary>
        /// <param name="sinacorReportDataSource">lista de dada sources</param>
        /// <param name="formatObjects">objetos de formatação</param>
        /// <param name="reportName">Nome do relatório, utilizado para carregar o rpt</param>
        /// <param name="columnMappedChecked">Indica se serão apresentadas legendas para as colunas</param>
        /// <param name="reportTitle">Título do relatório, deve sempre ser um resourceKey</param>
        public SinacorReportWindow(List<SinacorReportDataSource> sinacorReportDataSource, List<SinacorReportFormatObjects> formatObjects, String reportName, Boolean columnMappedChecked, String reportTitleResourceKey)
            : this(reportName, reportTitleResourceKey)
        {
            this.Loaded += new RoutedEventHandler(SinacorReportWindow_Loaded_GenericListDataGrid);

            this._sinacorReportDataSource = sinacorReportDataSource;
            this._formatObjects = formatObjects;
            this._columnMappedChecked = columnMappedChecked;
        }

        /// <summary>
        /// Criar uma nova SinacorReportWindow
        /// </summary>
        /// <param name="dataObjects">lista de data objects</param>
        /// <param name="formatObjects">Objetos de formatação</param>
        /// <param name="parametersValues">Parâmetros</param>
        /// <param name="reportName">Nome do relatório, utilizado para carregar o rpt</param>
        public SinacorReportWindow(List<SinacorReportDataObjects> dataObjects, List<SinacorReportFormatObjects> formatObjects, List<SinacorReportParameterValue> parametersValues, String reportName, String reportTitleResourceKey)
            : this(reportName, reportTitleResourceKey)
        {
            this.Loaded += new RoutedEventHandler(SinacorReportWindow_Loaded_ManualReport);

            this._formatObjects = formatObjects;
            this._dataObjects = dataObjects;
            this._parametersValues = parametersValues;
        }

        #endregion

        #region SinacorReportWindow_Loaded_ManualReport

        private String GetModule()
        {
            String[] itens = this._reportName.Split('.');
            return itens[2].ToString(); // Posição contendo o nome do módulo
        }

        void SinacorReportWindow_Loaded_ManualReport(object sender, RoutedEventArgs e)
        {
            this._reportDocument.Load(System.Windows.Forms.Application.StartupPath + @"\" + this.GetModule() + @"\Report\" + this._reportName + ".rpt");

            // Controle de visibilidade e estilo dos objetos do relatório
            this.ConfigManualReport(this._reportDocument.ReportDefinition.ReportObjects, String.Empty);

            // Carrega os dados do relatório
            foreach (SinacorReportDataObjects item in this._dataObjects)
            {
                if (String.IsNullOrEmpty(item.SubReportName))
                    this._reportDocument.Database.Tables[item.ReportTable].SetDataSource(item.Data);
                else
                    this._reportDocument.Subreports[item.SubReportName].Database.Tables[item.ReportTable].SetDataSource(item.Data);
            }

            // Carrega os parâmetros do relatório
            foreach (SinacorReportParameterValue item in this._parametersValues)
            {
                if (String.IsNullOrEmpty(item.SubReportName))
                    this._reportDocument.SetParameterValue(item.ParameterName, item.ParameterValue);
                else
                    this._reportDocument.SetParameterValue(item.ParameterName, item.ParameterValue, item.SubReportName);
            }

            this._crViewer.ReportSource = this._reportDocument;
        }

        private void ConfigTextObjectManualReport(TextObject textObject, SinacorReportFormatObjects item)
        {
            textObject.Text = item.TitleColumn;
            textObject.ObjectFormat.EnableSuppress = !item.IsVisible;
            this.ApplyStyleTextObject(textObject);
        }

        private void ConfigFieldObjectManualReport(FieldObject fieldObject, SinacorReportFormatObjects item)
        {
            fieldObject.ObjectFormat.EnableSuppress = !item.IsVisible;
            this.ApplyStyleFieldObject(fieldObject);
        }

        private void ConfigManualReport(ReportObjects reportObjects, String subReportName)
        {
            String propertyName = String.Empty;
            SinacorReportFormatObjects item = null;

            foreach (ReportObject reportObject in reportObjects)
            {
                if (reportObject is SubreportObject)
                {
                    String name = ((SubreportObject)reportObject).SubreportName;
                    this.ConfigManualReport(this._reportDocument.Subreports[name].ReportDefinition.ReportObjects, name);
                }
                else if (reportObject is TextObject || reportObject is FieldObject)
                {
                    propertyName = reportObject.Name.Substring(1, reportObject.Name.Length - 1);

                    if (String.IsNullOrEmpty(subReportName))
                        item = this._formatObjects.Find(x => x.PropertyName.Equals(propertyName));
                    else
                        item = this._formatObjects.Find(x => x.PropertyName.Equals(propertyName) && x.SubReportName.Equals(subReportName));

                    if (item != null)
                    {
                        if (reportObject is TextObject)
                            this.ConfigTextObjectManualReport((TextObject)reportObject, item);
                        else
                            this.ConfigFieldObjectManualReport((FieldObject)reportObject, item);
                    }
                }
            }
        }

        #endregion

        #region SinacorReportWindow_Loaded_GenericListDataGrid

        void SinacorReportWindow_Loaded_GenericListDataGrid(object sender, RoutedEventArgs e)
        {
            this._reportDocument.Load(System.Windows.Forms.Application.StartupPath + @"\Infra\Report\" + this._reportName + ".rpt");

            Int16 i = 1;
            Int16 j = 1;
            Int32 previousLeft = 0;
            Int32 previousWidth = 0;

            List<SinacorReportIndexDataSource> index = new List<SinacorReportIndexDataSource>();

            foreach (SinacorReportFormatObjects item in this._formatObjects)
            {
                if (item.IsVisible)
                {
                    // Título
                    using (TextObject to = (TextObject)this._reportDocument.ReportDefinition.ReportObjects["T" + i.ToString()])
                    {
                        if (this._columnMappedChecked)
                        {
                            index.Add(new SinacorReportIndexDataSource() { Index = j.ToString() + " - " + item.TitleColumn });
                            to.Text = j.ToString();
                            j++;
                        }
                        else
                            to.Text = item.TitleColumn;

                        to.ObjectFormat.HorizontalAlignment = (CrystalDecisions.Shared.Alignment)item.AlignmentColumn;
                        to.Width = 15 * item.WidthColumn; // 15 Twips = 1 Pixel
                        to.Left = i == 1 ? 50 : previousLeft + previousWidth + 100;
                        to.ObjectFormat.EnableSuppress = !item.IsVisible;
                        this.ApplyStyleTextObject(to);
                        previousLeft = to.Left;
                        previousWidth = to.Width;
                    }

                    // Campo
                    using (FieldObject fo = (FieldObject)this._reportDocument.ReportDefinition.ReportObjects["F" + i.ToString()])
                    {
                        fo.ObjectFormat.HorizontalAlignment = (CrystalDecisions.Shared.Alignment)item.AlignmentColumn;
                        fo.Width = previousWidth;
                        fo.Left = previousLeft;
                        fo.ObjectFormat.EnableCanGrow = item.FieldWrap;
                        fo.ObjectFormat.EnableSuppress = !item.IsVisible;
                        this.ApplyStyleFieldObject(fo);
                    }
                }
                i++;
            }

            // Carrega e aplica os dados do cabeçalho do relatório
            this.LoadReportHeader();

            // Carrega e aplica os dados do rodapé do relatório
            this.LoadReportFooter();

            // Aplica a cor da seção dos títulos das colunas
            this._reportDocument.ReportDefinition.Sections["PageHeaderSection1"].SectionFormat.BackgroundColor = (System.Drawing.Color)this._style["BackgroundTrackTitle"];

            // Aplica estilo na legenda, caso o usuário escolha visualizar as colunas mapeadas
            if (this._columnMappedChecked)
                this.LoadLegend("Legenda");

            // Aplica os dados da legenda
            this._reportDocument.Subreports["Legenda"].Database.Tables["Sinacor_Infra_UI_Controls_SmartClient_SinacorReportIndexDataSource"].SetDataSource(index);

            // Aplica os dados do relatório
            this._reportDocument.Database.Tables["Sinacor_Infra_UI_Controls_SmartClient_SinacorReportDataSource"].SetDataSource(this._sinacorReportDataSource);

            // Habilita legenda referentes as colunas mapeadas
            this._reportDocument.SetParameterValue("VisualizarLegenda", this._columnMappedChecked);

            // Aplica cores para montagem do relatório zebrado
            this._reportDocument.SetParameterValue("BackgroundColorStripe1", this._style["BackgroundColorStripe1"].ToString());
            this._reportDocument.SetParameterValue("BackgroundColorStripe2", this._style["BackgroundColorStripe2"].ToString());

            // Aplica o título do relatório
            this._reportDocument.SetParameterValue("TitleReport", (string)ResourceProviderManager.GetResourceProvider().TryGetResource(this._reportTitleResourceKey), "ReportHeader");

            // Visualiza relatório
            this._crViewer.ReportSource = this._reportDocument;
        }

        #endregion

        #region LoadLegend

        private void LoadLegend(String subReportName)
        {
            foreach (ReportObject reportObject in this._reportDocument.Subreports[subReportName].ReportDefinition.ReportObjects)
            {
                if (reportObject is TextObject)
                    this.ApplyStyleTextObject((TextObject)reportObject);
                else if (reportObject is FieldObject)
                    this.ApplyStyleFieldObject((FieldObject)reportObject);
            }
        }

        #endregion

        #region LoadReportHeader

        private void LoadReportHeader()
        {
            try
            {
                using (FieldObject reportTitle = (FieldObject)this._reportDocument.Subreports["ReportHeader"].ReportDefinition.ReportObjects["TitleReport"])
                {
                    reportTitle.Color = (System.Drawing.Color)this._style["ReportTitleFontColor"];

                    using (Font fonte = new Font(this._style["ReportTitleFontName"].ToString(), Single.Parse(this._style["ReportTitleFontSize"].ToString()), (System.Drawing.FontStyle)this._style["ReportTitleFontStyle"]))
                    {
                        reportTitle.ApplyFont(fonte);
                    }
                }

                this._reportDocument.Subreports["ReportHeader"].ReportDefinition.ReportObjects["LineTitleTop"].Border.BackgroundColor = (System.Drawing.Color)this._style["BackgroundReportTitleLineTop"];
                this._reportDocument.Subreports["ReportHeader"].ReportDefinition.ReportObjects["LineTitleBottom"].Border.BackgroundColor = (System.Drawing.Color)this._style["BackgroundReportTitleLineBottom"];
            }
            catch (Exception)
            { }
        }

        #endregion

        #region LoadReportFooter

        private void LoadReportFooter()
        {
            try
            {
                this._reportDocument.Subreports["ReportFooter"].ReportDefinition.ReportObjects["LinePageFooter"].Border.BackgroundColor = (System.Drawing.Color)this._style["BackgroundReportFooterLine"];
            }
            catch (Exception)
            { }
        }

        #endregion

        #region ApplyStyleTextObject

        private void ApplyStyleTextObject(TextObject textObject)
        {
            String cssClass = textObject.ObjectFormat.CssClass;

            if (!String.IsNullOrEmpty(cssClass))
            {
                try
                {
                    // Font
                    using (Font fonte = new Font(this._style[cssClass + "FontName"].ToString(), Single.Parse(this._style[cssClass + "FontSize"].ToString()), (System.Drawing.FontStyle)this._style[cssClass + "FontStyle"]))
                    {
                        textObject.ApplyFont(fonte);
                    }
                    textObject.Color = (System.Drawing.Color)this._style[cssClass + "FontColor"];

                    // Border
                    textObject.Border.BackgroundColor = (System.Drawing.Color)this._style[cssClass + "BackgroundColor"];
                    textObject.Border.BorderColor = (System.Drawing.Color)this._style[cssClass + "BorderColor"];
                    textObject.Border.BottomLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    textObject.Border.TopLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    textObject.Border.LeftLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    textObject.Border.RightLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                }
                catch (Exception ex)
                { }
            }
        }

        #endregion

        #region ApplyStyleFieldObject

        private void ApplyStyleFieldObject(FieldObject fieldObject)
        {
            String cssClass = fieldObject.ObjectFormat.CssClass;

            if (!String.IsNullOrEmpty(cssClass))
            {
                try
                {
                    // Font
                    using (Font fonte = new Font(this._style[cssClass + "FontName"].ToString(), Single.Parse(this._style[cssClass + "FontSize"].ToString()), (System.Drawing.FontStyle)this._style[cssClass + "FontStyle"]))
                    {
                        fieldObject.ApplyFont(fonte);
                    }
                    fieldObject.Color = (System.Drawing.Color)this._style[cssClass + "FontColor"];

                    // Border
                    fieldObject.Border.BackgroundColor = (System.Drawing.Color)this._style[cssClass + "BackgroundColor"];
                    fieldObject.Border.BorderColor = (System.Drawing.Color)this._style[cssClass + "BorderColor"];
                    fieldObject.Border.BottomLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    fieldObject.Border.TopLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    fieldObject.Border.LeftLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                    fieldObject.Border.RightLineStyle = CrystalDecisions.Shared.LineStyle.SingleLine;
                }
                catch (Exception ex)
                { }
            }
        }

        #endregion

        #region Barra de Botões

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void btnExport_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.ExportReport();
        }

        private void btnPrint_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.PrintReport();
        }

        private void btnGroupTree_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.DisplayGroupTree = !this._crViewer.DisplayGroupTree;
        }

        private void btnFirst_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.ShowFirstPage();
        }

        private void btnPrevious_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.ShowPreviousPage();
        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.ShowNextPage();
        }

        private void btnLast_Click(object sender, RoutedEventArgs e)
        {
            this._crViewer.ShowLastPage();
        }

        #endregion

        #region OnApplyTemplate

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this._crViewer = new CrystalReportViewer();
            this._crViewer.DisplayStatusBar = false;
            this._crViewer.DisplayToolbar = false;
            this._crViewer.DisplayGroupTree = false;

            WindowsFormsHost hostReportViewer = this.GetTemplateChild("HostReportViewer") as WindowsFormsHost;
            hostReportViewer.Child = this._crViewer;

            DockPanel header = this.GetTemplateChild("LayoutRoot") as DockPanel;
            header.MouseLeftButtonDown += new MouseButtonEventHandler(header_MouseLeftButtonDown);
        }

        #region header_MouseLeftButtonDown

        void header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }

        #endregion

        #endregion
    }
}
